package pow;

import beans.BlockBean;
import beans.NonceAndHash;
import beans.ProofOfWork;
import utils.ByteArrToHexString;
import utils.Hash;

import java.math.BigInteger;

/**
 * @author:zhengyilong
 * @email:1797344574@qq.com
 * @phone:13479394730
 * @desc:
 * @DateTime:2022/5/14 15:47
 **/
public class pow {

    //挖矿难度
    private final static int targetBits = 5;

    //实例化一个pow对象，并返回
    public static ProofOfWork NewProofOfwork(BlockBean block){
        //初始化一个大整数类型的1+
        BigInteger target = new BigInteger("1");
        //哈希值 256 - 1 - bits	255 - bits
        target = target.shiftLeft(255 - targetBits);

        return  new ProofOfWork(block,target);
    }

    //用来寻找随机数的，返回一个哈希值和一个随机数
    public static NonceAndHash Run(ProofOfWork proofOfWork){
        //获取到区块
        BlockBean block = proofOfWork.getBlock();
        //将long类型的时间戳转成字节数组类型
        byte[] timestamp = Long.toString(block.getTimestamp()).getBytes();
        //声明随机数
        int nonce = 0;

        while (true){
            //将int类型的随机数转换成字节数组类型
            byte[] nonceBytes = Integer.toHexString(nonce).getBytes();

            //声明一个长度为四个字段总长度的数组
            //两次判空，防止创建的是创世区块，没有上一个区块哈希值报空指针异常
            byte[] bytes;
            if (block.getPrevBlockHash() != null){
                bytes = new byte[timestamp.length+block.getData().length+block.getPrevBlockHash().length+nonceBytes.length];
            }else {
                bytes = new byte[timestamp.length+block.getData().length+nonceBytes.length];
            }

            /**
             * 将区块所有字段和随机数拼接
             * 第一个参数：原数组
             * 第二个参数：从原数组的起始位置开始
             * 第三个参数：目标数组
             * 第四个参数：目标数组的开始起始位置
             * 第五个参数：要copy的数组的长度
             */
            System.arraycopy(timestamp,0,bytes,0,timestamp.length);
            System.arraycopy(block.getData(),0,bytes,timestamp.length,block.getData().length);
            System.arraycopy(nonceBytes,0,bytes,timestamp.length+block.getData().length,nonceBytes.length);
            //两次判空，防止创建的是创世区块，没有上一个区块哈希值报空指针异常
            if (block.getPrevBlockHash() != null){
                System.arraycopy(block.getPrevBlockHash(),0,bytes,timestamp.length+block.getData().length+nonceBytes.length,block.getPrevBlockHash().length);
            }

            //对拼接后的字节数组进行哈希计算
            byte[] hash = Hash.SHA256(bytes);

            //转换成大整数类型
            String byteArrToHexString = ByteArrToHexString.getByteArrToHexString(hash);
            BigInteger bighash = new BigInteger(byteArrToHexString,16);
            //如果bighash<proofOfWork.getTarget()，返回-1，则返回
            if (bighash.compareTo(proofOfWork.getTarget()) == -1){
                return new NonceAndHash(nonce,hash);
            }
            System.out.printf("正在寻找nonce,当前的nonce为：%d\n",nonce);
            //否则继续寻找
            nonce++;
        }
    }

}

